package com.frog.framework.s3;

import com.frog.framework.s3.factory.S3EndpointFactory;
import com.frog.framework.s3.model.S3ObjectInfo;
import org.springframework.util.Assert;
import software.amazon.awssdk.core.ResponseBytes;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.services.s3.model.*;

import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

/**
 * @author wuqiong 2022/3/3
 * @description
 */
public class FrogS3Client {

    public static String uploadFile(String bucketName, String key, byte[] byteFile) {
        return uploadFile(null, bucketName, key, byteFile);
    }

    /**
     * 上传文件
     *
     * @param clientName 使用的s3链接 ,不写使用默认的
     * @param bucketName 桶的名称
     * @param key        key名称
     * @param byteFile   文件字节流
     * @return String 返回文件的eTag值
     * @author wuqiong 2022/10/26 18:29
     */
    public static String uploadFile(String clientName, String bucketName, String key, byte[] byteFile) {
        Assert.hasText(bucketName, "参数 bucketName 值不能为空,请检查");
        Assert.hasText(key, "参数 key 值不能为空,请检查");
        Assert.isTrue(byteFile.length > 1, "参数 byteFile 值不能为空,请检查");
        PutObjectRequest objectRequest = PutObjectRequest.builder()
                .bucket(bucketName)
                .key(key)
                .build();
        try {
            PutObjectResponse putObjectResponse = S3EndpointFactory.getS3Client(clientName).putObject(objectRequest, RequestBody.fromBytes(byteFile));
            return putObjectResponse != null && putObjectResponse.sdkHttpResponse().isSuccessful() ? putObjectResponse.eTag() : null;
        } catch (S3Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String uploadFile(String bucketName, String key, File file) {
        return uploadFile(null, bucketName, key, file);
    }

    /**
     * 上传文件
     *
     * @param clientName 使用的s3链接 ,不写使用默认的
     * @param bucketName 桶的名称
     * @param key        key名称
     * @param file       文件
     * @return String 返回文件的eTag值
     * @author wuqiong 2022/10/26 18:29
     */
    public static String uploadFile(String clientName, String bucketName, String key, File file) {
        Assert.hasText(bucketName, "参数 bucketName 值不能为空,请检查");
        Assert.hasText(key, "参数 key 值不能为空,请检查");
        Assert.isTrue(file != null, "参数 file 值不能为空,请检查");
        PutObjectRequest objectRequest = PutObjectRequest.builder()
                .bucket(bucketName)
                .key(key)
                .build();
        try {
            PutObjectResponse putObjectResponse = S3EndpointFactory.getS3Client(clientName)
                    .putObject(objectRequest, RequestBody.fromFile(file));
            return putObjectResponse != null && putObjectResponse.sdkHttpResponse().isSuccessful() ? putObjectResponse.eTag() : null;
        } catch (S3Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 下载文件 (得到 byte流)
     *
     * @param clientName 使用的s3链接 ,不写使用默认的
     * @param bucketName 桶的名称
     * @param key        key名称
     * @return byte[] 返回文件字节流
     * @author wuqiong 2022/10/26 18:34
     */
    public static byte[] downloadFileBytes(String clientName, String bucketName, String key) {
        Assert.hasText(bucketName, "参数 bucketName 值不能为空,请检查");
        Assert.hasText(key, "参数 key 值不能为空,请检查");
        try {
            GetObjectRequest request = GetObjectRequest.builder().key(key).build();
            ResponseBytes<GetObjectResponse> objectBytes = S3EndpointFactory.getS3Client(clientName).getObjectAsBytes(request);
            return objectBytes != null && objectBytes.response().sdkHttpResponse().isSuccessful() ? objectBytes.asByteArray() : null;
        } catch (S3Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 下载文件 (得到 File 文件)
     *
     * @param clientName 使用的s3链接 ,不写使用默认的
     * @param bucketName 桶的名称
     * @param key        key名称
     * @param outputPath 输出文件的地址
     * @return file 返回文件
     * @author wuqiong 2023/1/5 16:16
     */
    public static File downloadFile(String clientName, String bucketName, String key, String outputPath) {
        Assert.hasText(bucketName, "参数 bucketName 值不能为空,请检查");
        Assert.hasText(key, "参数 key 值不能为空,请检查");
        Assert.hasText(outputPath, "参数 outputPath 值不能为空,请检查");
        try {
            GetObjectRequest request = GetObjectRequest.builder().bucket(bucketName).key(key).build();
            ResponseBytes<GetObjectResponse> objectBytes = S3EndpointFactory.getS3Client(clientName).getObjectAsBytes(request);
            // 文件可能不存在,或者获取失败
            if (objectBytes == null || !objectBytes.response().sdkHttpResponse().isSuccessful()) {
                return null;
            }
            File resultFile = new File(outputPath);
            OutputStream os = new FileOutputStream(resultFile);
            os.write(objectBytes.asByteArray());
            os.close();// Close the file
            return resultFile;
        } catch (S3Exception | IOException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 获取文件属性
     *
     * @param clientName 使用的s3链接 ,不写使用默认的
     * @param bucketName 桶的名称
     * @param key        key名称
     * @return S3ObjectInfo 返回文件基本信息类
     * @author wuqiong 2022/10/26 18:34
     */
    public static S3ObjectInfo getBucketFileInfo(String clientName, String bucketName, String key) {
        Assert.hasText(bucketName, "参数 bucketName 值不能为空,请检查");
        Assert.hasText(key, "参数 key 值不能为空,请检查");
        try {
            HeadObjectRequest request = HeadObjectRequest.builder()
                    .bucket(bucketName)
                    .key(key)
                    .build();
            HeadObjectResponse headObjectResponse = S3EndpointFactory.getS3Client(clientName).headObject(request);
            S3ObjectInfo s3ObjectInfo = new S3ObjectInfo();
            s3ObjectInfo.setContentType(headObjectResponse.contentType());
            s3ObjectInfo.seteTag(headObjectResponse.eTag().replaceAll("\"", ""));
            s3ObjectInfo.setLastModified(headObjectResponse.lastModified().toEpochMilli());
            s3ObjectInfo.setContentLength(headObjectResponse.contentLength());
            s3ObjectInfo.setDeleteMarker(headObjectResponse.deleteMarker());
            return s3ObjectInfo;
        } catch (S3Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 判断是否存在文件
     *
     * @param clientName 使用的s3链接 ,不写使用默认的
     * @param bucketName 桶的名称
     * @param key        key名称
     * @return boolean 返回文件是否存在
     * @author wuqiong 2022/10/26 18:34
     */
    public static boolean isExistObject(String clientName, String bucketName, String key) {
        Assert.hasText(bucketName, "参数 bucketName 值不能为空,请检查");
        Assert.hasText(key, "参数 key 值不能为空,请检查");
        try {
            HeadObjectRequest request = HeadObjectRequest.builder()
                    .bucket(bucketName)
                    .key(key)
                    .build();
            HeadObjectResponse headObjectResponse = S3EndpointFactory.getS3Client(clientName).headObject(request);
            return headObjectResponse.sdkHttpResponse().isSuccessful();
        } catch (S3Exception e) {
            if (e.awsErrorDetails() == null || !e.awsErrorDetails().errorCode().equals("NoSuchKey")) {
                e.printStackTrace();
            }
        }
        return false;
    }


    /**
     * 删除文件
     *
     * @param clientName 使用的s3链接 ,不写使用默认的
     * @param bucketName 桶的名称
     * @param key        key名称
     * @return boolean  返回删除标记
     * @author wuqiong 2022/10/26 18:40
     */
    public static boolean deleteBucketFile(String clientName, String bucketName, String key) {
        Assert.hasText(bucketName, "参数 bucketName 值不能为空,请检查");
        Assert.hasText(key, "参数 key 值不能为空,请检查");
        try {
            DeleteObjectRequest request = DeleteObjectRequest.builder()
                    .bucket(bucketName)
                    .key(key)
                    .build();
            DeleteObjectResponse deleteResponse = S3EndpointFactory.getS3Client(clientName).deleteObject(request);
            return deleteResponse != null && deleteResponse.sdkHttpResponse().isSuccessful() ? deleteResponse.deleteMarker() : false;
        } catch (S3Exception e) {
            e.printStackTrace();
        }
        return false;
    }


    /**
     * 复制文件到另一个桶中
     *
     * @param clientName     使用的s3链接 ,不写使用默认的
     * @param fromBucketName 原始桶的名称
     * @param fromKey        原始key名称
     * @param toBucketName   目标桶的名称
     * @param toKey          目标key名称
     * @return boolean  返回删除标记
     * @author wuqiong 2022/10/26 18:40
     */
    public static String copyBucketFile(String clientName, String fromBucketName, String fromKey, String toBucketName, String toKey) {
        Assert.hasText(fromBucketName, "参数 fromBucketName 值不能为空,请检查");
        Assert.hasText(toBucketName, "参数 toBucketName 值不能为空,请检查");
        Assert.hasText(fromKey, "参数 fromKey 值不能为空,请检查");
        Assert.hasText(toKey, "参数 toKey 值不能为空,请检查");
        try {
            String encodedUrl = "";
            try {
                encodedUrl = URLEncoder.encode(fromBucketName + "/" + fromKey, StandardCharsets.UTF_8.toString());
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            CopyObjectRequest copyRequest = CopyObjectRequest.builder()
                    .copySourceIfMatch(encodedUrl)
                    .destinationBucket(toBucketName)
                    .destinationKey(toKey)
                    .build();
            CopyObjectResponse copyResponse = S3EndpointFactory.getS3Client(clientName).copyObject(copyRequest);
            return copyResponse != null && copyResponse.sdkHttpResponse().isSuccessful() ? copyResponse.copyObjectResult().toString() : null;
        } catch (S3Exception e) {
            e.printStackTrace();
        }
        return null;
    }


}
